package euler.p001_050;

import euler.MainEuler;

public class Euler028 extends MainEuler {

    /*
        Starting with the number 1 and moving to the right i
        n a clockwise direction a 5 by 5 spiral is formed as follows:

        21 22 23 24 25
        20  7  8  9 10
        19  6  1  2 11
        18  5  4  3 12
        17 16 15 14 13

        It can be verified that the sum of the
        numbers on the diagonals is 101.

        What is the sum of the numbers on the diagonals
        in a 1001 by 1001 spiral formed in the same way?

     */
    private static class Trio {

        private final int fila;
        private final int columna;
        private final int valor;

        public Trio(int fila, int columna, int valor) {
            this.fila = fila;
            this.columna = columna;
            this.valor = valor;
        }

        public int getFila() {
            return this.fila;
        }
        public int getColumna() {
            return this.columna;
        }
        public int getValor() {
            return this.valor;
        }
    }


    public String resolve(int size) {

        int[][] matrix = new int[size][size];

        int valor = size*size;

        Trio trio = llenarIzquierda(matrix,0,size-1,valor);

        while (trio.getValor() > 1) {
            trio = llenarAbajo(matrix,trio.getFila(),trio.getColumna(),trio.getValor());
            trio = llenarDerecha(matrix,trio.getFila(),trio.getColumna(),trio.getValor());
            trio = llenarArriba(matrix,trio.getFila(),trio.getColumna(),trio.getValor());
            trio = llenarIzquierda(matrix,trio.getFila(),trio.getColumna(),trio.getValor());
        }

        int suma = -1;

        for (int i = 0; i < matrix.length; i++) {
            suma+=matrix[i][i];
            suma+=matrix[matrix.length - 1 - i][i];
        }

        return String.valueOf(suma);
    }


    private Trio llenarArriba(int[][] matrix, int fila, int columna, int valor) {
        if (valor == 1) {
            return new Trio(fila, columna, valor);
        }

        int ultimaFila = 1;
        matrix[fila][columna] = 0;

        for (int i = fila; (i >= 0) && (matrix[i][columna] == 0); i--) {
            matrix[i][columna] = valor--;
            ultimaFila = i;
        }

        return new Trio(ultimaFila, columna, valor+1);
    }


    private Trio llenarDerecha(int[][] matrix, int fila, int columna, int valor) {
        if (valor == 1) {
            return new Trio(fila, columna, valor);
        }

        int ultimaColumna = 1;
        matrix[fila][columna] = 0;

        for (int j = columna; (j < matrix[fila].length) && (matrix[fila][j] == 0); j++) {
            matrix[fila][j] = valor--;
            ultimaColumna = j;
        }

        return new Trio(fila, ultimaColumna, valor+1);
    }


    private Trio llenarAbajo(int[][] matrix, int fila, int columna, int valor) {

        if (valor == 1) {
            return new Trio(fila, columna, valor);
        }

        int ultimaFila = 1;
        matrix[fila][columna] = 0;

        for (int i = fila; (i < matrix.length) && (matrix[i][columna] == 0); i++) {
            matrix[i][columna] = valor--;
            ultimaFila = i;
        }

        return new Trio(ultimaFila, columna, valor+1);
    }


    private Trio llenarIzquierda(int[][] matrix, int fila, int columna, int valor) {

        if (valor == 1) {
            return new Trio(fila, columna, valor);
        }

        int ultimaColumna = 1;
        matrix[fila][columna] = 0;

        for (int j = columna; (j >= 0) && (matrix[fila][j] == 0); j--) {
            matrix[fila][j] = valor--;
            ultimaColumna = j;
        }

        return new Trio(fila, ultimaColumna, valor+1);
    }

}
